package com.reebake.ideal.security.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.reebake.ideal.security.authentication.LoginAuthenticationFailureHandler;
import com.reebake.ideal.security.authentication.LoginAuthenticationSuccessHandler;
import com.reebake.ideal.security.authentication.SmartLoginAuthenticationFilter;
import com.reebake.ideal.security.authentication.SmartLogoutSuccessHandler;
import com.reebake.ideal.security.properties.ServerSecurityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

@Configuration
@Slf4j
public class ServerAuthenticationFilterConfig {

	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private AuthenticationManager authenticationManager;
	@Autowired
    private ApplicationEventPublisher applicationEventPublisher;
	@Autowired
	private ServerSecurityProperties serverSecurityProperties;

    @Bean
	SecurityFilterChain authorizationSecurityFilterChain(HttpSecurity http) throws Exception {
		log.info("启动SecurityFilterChain: authorization-server");
		http.securityMatcher(serverSecurityProperties.getFormLoginUrl()
                        , serverSecurityProperties.getFormLogoutUrl(), serverSecurityProperties.getTokenRefreshUrl()
                )
                .formLogin(formLogin -> formLogin.loginPage(serverSecurityProperties.getFormLoginUrl()))
                .logout(logout -> {
					logout.logoutUrl(serverSecurityProperties.getFormLogoutUrl()).logoutSuccessHandler(logoutSuccessHandler());
				})
                .authorizeHttpRequests(authorizeHttpRequests ->
                        authorizeHttpRequests.requestMatchers(serverSecurityProperties.getFormLoginUrl()
                                        , serverSecurityProperties.getTokenRefreshUrl()
                                ).permitAll()
                                .anyRequest().authenticated()
                )
                .addFilterBefore(smartLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
        ;

        http.csrf(csrf -> csrf.disable());
        http.cors(Customizer.withDefaults());
		return http.build();
	}

	public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new LoginAuthenticationSuccessHandler(applicationEventPublisher, serverSecurityProperties);
	}

	public AuthenticationFailureHandler authenticationFailureHandler() {
        return new LoginAuthenticationFailureHandler(applicationEventPublisher, objectMapper);
	}

    public LogoutSuccessHandler logoutSuccessHandler() {
        return new SmartLogoutSuccessHandler();
	}

	public SmartLoginAuthenticationFilter smartLoginAuthenticationFilter() {
		SmartLoginAuthenticationFilter smartLoginAuthenticationFilter = new SmartLoginAuthenticationFilter(serverSecurityProperties.getFormLoginUrl());
		smartLoginAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
		smartLoginAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
		smartLoginAuthenticationFilter.setAuthenticationManager(authenticationManager);
		smartLoginAuthenticationFilter.setObjectMapper(objectMapper);
		smartLoginAuthenticationFilter.setServerSecurityProperties(serverSecurityProperties);

		return smartLoginAuthenticationFilter;
	}

}
